// Types.h
//------------------------------------------------------------------------------
#pragma once

#if defined( __LINUX__ ) || defined( __OSX__ )
    #include <sys/types.h>
#endif

typedef unsigned char       uint8_t;
typedef signed char         int8_t;
typedef unsigned short      uint16_t;
typedef signed short        int16_t;
typedef unsigned int        uint32_t;
typedef signed int          int32_t;
#if defined( __WINDOWS__ ) || defined( __OSX__ )
    typedef unsigned long long  uint64_t;
    typedef signed long long    int64_t;
    #ifndef PRIi64
        #define PRIi64 "lli"
    #endif
    #ifndef PRIu64
        #define PRIu64 "llu"
    #endif
    #ifndef PRIx64
        #define PRIx64 "llx"
    #endif
    #ifndef PRIX64
        #define PRIX64 "llX"
    #endif
#else
    typedef unsigned long int   uint64_t;
    typedef signed long int     int64_t;
    #ifndef PRIi64
        #define PRIi64 "li"
    #endif
    #ifndef PRIu64
        #define PRIu64 "lu"
    #endif
    #ifndef PRIx64
        #define PRIx64 "lx"
    #endif
    #ifndef PRIX64
        #define PRIX64 "lX"
    #endif
#endif

#define KILOBYTE (1024)
#define MEGABYTE (1024 * 1024)

#if defined( __WINDOWS__ )
    #define THREAD_LOCAL __declspec( thread )
#else
    #define THREAD_LOCAL __thread
#endif

#if defined( __WINDOWS__ )
    #define NO_INLINE __declspec( noinline )
    #define FORCE_INLINE __forceinline
#elif defined( __APPLE__ ) || defined( __LINUX__ )
    #define NO_INLINE inline __attribute__((noinline))
    #define FORCE_INLINE inline __attribute__((always_inline))
#endif

#if defined( __clang__ )
    #define NORETURN_CLANG_ANALYZER __attribute__((analyzer_noreturn))
#else
    #define NORETURN_CLANG_ANALYZER
#endif

#if defined( __APPLE__ ) || defined( __LINUX__ )
    #include <stddef.h> // needed for size_t
#endif

#ifndef intptr_t
    #if defined( __WINDOWS__ )
        typedef int64_t     intptr_t;
        typedef uint64_t    uintptr_t;
    #endif
#endif
#ifndef uintptr_t
    #if defined( __LINUX__ )
        typedef uint64_t    uintptr_t;
    #endif
#endif
#ifndef size_t
    #if defined( __WINDOWS__ )
        typedef uint64_t    size_t;
    #endif
#endif

#ifndef LONGLONG
    typedef long long LONGLONG;
#endif

#if defined( __GNUC__ ) || defined( __clang__ ) // GCC or Clang
    #define FORMAT_STRING( fmt, args ) __attribute__((format(printf, fmt, args)))
    #define SCAN_STRING( fmt, args ) __attribute__((format(scanf, fmt, args)))
#else
    #define FORMAT_STRING( fmt, args )
    #define SCAN_STRING( fmt, args )
#endif

#define ARRAY_SIZE( array ) ( sizeof( array ) / sizeof( array[0] ) )

// Warning disabling
//------------------------------------------------------------------------------
#if defined( __WINDOWS__ )
    #define PRAGMA_DISABLE_PUSH_MSVC( num ) __pragma(warning(push))         \
                                            __pragma(warning(disable:num))
    #define PRAGMA_DISABLE_POP_MSVC         __pragma(warning(pop))
#else
    // Do nothing on non-msvc platforms
    #define PRAGMA_DISABLE_PUSH_MSVC( num )
    #define PRAGMA_DISABLE_POP_MSVC
#endif
#if defined( __clang__ )
    #define PRAGMA_DO( p ) _Pragma( #p )
    #define PRAGMA_DISABLE_PUSH_CLANG( w )  PRAGMA_DO( clang diagnostic push ) \
                                            PRAGMA_DO( clang diagnostic ignored w )
    #define PRAGMA_DISABLE_POP_CLANG        PRAGMA_DO( clang diagnostic pop )
#else
    #define PRAGMA_DISABLE_PUSH_CLANG( w )
    #define PRAGMA_DISABLE_POP_CLANG
#endif
#if defined( __WINDOWS__ ) && defined( __clang__ )
    #define PRAGMA_DISABLE_PUSH_CLANG_WINDOWS( w )  __pragma( clang diagnostic push ) \
                                                    __pragma( clang diagnostic ignored w )
    #define PRAGMA_DISABLE_POP_CLANG_WINDOWS        __pragma( clang diagnostic pop )
#else
    #define PRAGMA_DISABLE_PUSH_CLANG_WINDOWS( w )
    #define PRAGMA_DISABLE_POP_CLANG_WINDOWS
#endif

//------------------------------------------------------------------------------
